home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / TTYDRIV.C < prev    next >
C/C++ Source or Header  |  1990-08-28  |  9KB  |  381 lines

  1. /* TTY input driver */
  2.  
  3. #include <stdio.h>
  4. #include <ctype.h>
  5. #include "global.h"
  6.  
  7. int ttymode;
  8. #define TTY_COOKED    0
  9. #define TTY_RAW 1
  10.  
  11. #define LINESIZE    256
  12. #define MAXHIST        25
  13.  
  14. #define CTLR        18
  15. #define CTLX        24
  16. #define CTLU        21
  17. #define CTLV        22
  18. #define CTLW        23
  19. #define CTLZ        26
  20.  
  21. struct linehist
  22. {
  23.     struct linehist *next;
  24.     struct linehist *prev;
  25.     char linebuf[1];
  26. };
  27. #define NULLHIST    (struct linehist *)0
  28.  
  29. struct linehist *linehist = NULLHIST;
  30.  
  31. raw()
  32. {
  33.     ttymode = TTY_RAW;
  34. }
  35.  
  36. cooked()
  37. {
  38.     ttymode = TTY_COOKED;
  39. }
  40.  
  41. static void echochar (c)        /* echo character */
  42.     unsigned char c;
  43.  
  44. {
  45.     if (c < ' ') {            /* a control char? */
  46.        putchar('^');            /* show as ^char */
  47.        c += 64;
  48.     }
  49.  
  50.     putchar(c);
  51. }
  52.  
  53. static void bschar (c)            /* backspace over character */
  54.     unsigned char c;
  55.  
  56. {
  57.     if (c < ' ')            /* a control char? */
  58.     putchar('\b');            /* 2 backspaces needed */
  59.  
  60.     putchar('\b');
  61. }
  62.  
  63. static void erachar (c)            /* erase character */
  64.     unsigned char c;
  65.  
  66. {
  67.     if (c < ' ')            /* a control char? */
  68.     putchar(' ');            /* 2 spaces needed */
  69.  
  70.     putchar(' ');
  71.  
  72.     if (c < ' ')            /* a control char? */
  73.     putchar('\b');            /* 2 backspaces needed */
  74.  
  75.     putchar('\b');
  76. }
  77.  
  78. /* Accept characters from the incoming tty buffer and process them
  79.  * (if in cooked mode) or just pass them directly (if in raw mode).
  80.  * Returns the number of characters available for use; if non-zero,
  81.  * also stashes a pointer to the character(s) in the "buf" argument.
  82.  */
  83.  /*Control-R added by df for retype of lines - useful in Telnet */
  84.  /* full editing and history added by PE1CHL */
  85.  
  86. int
  87. ttydriv(c,buf)
  88. int  c;
  89. char **buf;
  90. {
  91.     static char linebuf[LINESIZE + 1];
  92.     static char *cp = linebuf;
  93.     static struct linehist *lh = NULLHIST;
  94.     static char insmode = 0;
  95.     static char quote = 0;
  96.     static int tailchars = 0;
  97.     register char *p,*q;
  98.     int cnt,i,seenprint;
  99.  
  100.     if(c == -1)            /* -1 is used to inquire buffered chars */
  101.     return((int) (cp - linebuf) + tailchars);
  102.  
  103. #ifdef DEBUG
  104.     if(buf == (char **)NULL)
  105.     return 0;        /* paranoia check */
  106. #endif
  107.  
  108.     /* initialize buffer when 1st call for this line */
  109.     if(cp == linebuf && !tailchars){
  110.     memset(linebuf,0,LINESIZE);
  111.     if((lh = linehist) != NULLHIST)
  112.         strcpy(linebuf,lh->linebuf);
  113.     }
  114.  
  115.     cnt = 0;
  116.     switch(ttymode){
  117.     case TTY_RAW:
  118.     tailchars = 0;        /* clear the COOKED line buffer */
  119.     insmode = quote = 0;
  120.     cp = linebuf;
  121.     switch(c){
  122.     case -20:        /* HOME key */
  123.         strcpy(linebuf,"\033[H");
  124.         cp += 3;
  125.         break;
  126.     case -19:        /* UP arrow */
  127.         strcpy(linebuf,"\033[A");
  128.         cp += 3;
  129.         break;
  130.     case -17:        /* LEFT arrow */
  131.         strcpy(linebuf,"\033[D");
  132.         cp += 3;
  133.         break;
  134.     case -16:        /* RIGHT arrow */
  135.         strcpy(linebuf,"\033[C");
  136.         cp += 3;
  137.         break;
  138.     case -14:        /* DOWN arrow */
  139.         strcpy(linebuf,"\033[B");
  140.         cp += 3;
  141.         break;
  142.     default:        /* a normal character */
  143.         *cp++ = c;
  144.         break;
  145.     }
  146.     cnt = (int) (cp - linebuf); /* return count of characters */
  147.     break;
  148.  
  149.     case TTY_COOKED:
  150.     /* Perform cooked-mode line editing */
  151.     if (quote)        /* prev char was quote? (^V) */
  152.         goto storechar;    /* then store anything */
  153.  
  154.     switch(c){
  155.     case '\r':        /* CR and LF are equivalent */
  156.     case '\n':
  157.         while(tailchars > 0){ /* move to end of line */
  158.         echochar(*cp++);
  159.         tailchars--;
  160.         }
  161.         *cp++ = '\r';
  162.         *cp++ = '\n';
  163.         *cp = '\0';
  164.         printf("\n");
  165.         cnt = (int) (cp - linebuf);
  166.         cp = linebuf;
  167.         if(cnt > 3){
  168.         i = 0;
  169.         for(lh = linehist; lh != NULLHIST; lh = lh->next){
  170.             if(!strcmp(lh->linebuf,linebuf) || ++i > MAXHIST){
  171.             if(lh->prev != NULLHIST)
  172.                 lh->prev->next = lh->next;
  173.             else
  174.                 linehist = lh->next;
  175.  
  176.             if(lh->next != NULLHIST)
  177.                 lh->next->prev = lh->prev;
  178.             free(lh);
  179.             }
  180.         }
  181.         if((lh = (struct linehist *) malloc(sizeof(struct linehist) + cnt)) != NULLHIST){
  182.             if((lh->next = linehist) != NULLHIST)
  183.             lh->next->prev = lh;
  184.             lh->prev = NULLHIST;
  185.             linehist = lh;
  186.             strcpy(lh->linebuf,linebuf);
  187.         }
  188.         }
  189.         insmode = 0;
  190.         break;
  191.     case 0x7f:        /* Delete */
  192.         if (tailchars > 0){
  193.         tailchars--;
  194.         c = *cp;
  195.         for(i = 0, p = cp, q = cp + 1; i < tailchars; i++){
  196.             echochar(p[1]);
  197.             *p++ = *q++;
  198.         }
  199.         erachar(c);
  200.         *p = '\0';
  201.         for(i = 0; i < tailchars; i++)
  202.             bschar(*--p);
  203.         } else {
  204.         goto storechar;
  205.         }
  206.         break;
  207.     case '\b':        /* Backspace */
  208.         if(cp != linebuf){
  209.         bschar(c = *--cp);
  210.         for(i = 0, p = cp, q = cp + 1; i < tailchars; i++){
  211.             echochar(p[1]);
  212.             *p++ = *q++;
  213.         }
  214.         erachar(c);
  215.         *p = '\0';
  216.         for(i = 0; i < tailchars; i++)
  217.             bschar(*--p);
  218.         }
  219.         break;
  220.     case CTLR:        /* print line buffer */
  221.         echochar(c);    /* ^R */
  222.         putchar('\n');
  223.         p = linebuf;
  224.         cp += tailchars;
  225.         while(p < cp)
  226.         echochar(*p++);
  227.         tailchars = 0;
  228.         break;
  229.     case CTLU:        /* Line kill */
  230.     case CTLX:        /* Also a line kill */
  231.         while(tailchars > 0){
  232.         echochar(*cp++);
  233.         tailchars--;
  234.         }
  235.         while(cp != linebuf){
  236.         bschar(*--cp);
  237.         erachar(*cp);
  238.         }
  239.         break;
  240.     case CTLV:        /* Literal Next */
  241.         quote = 1;
  242.         c = '^';        /* insert a ^ temporarily */
  243.         goto storechar;
  244.     case CTLW:        /* Word Erase */
  245.         seenprint = 0;    /* Haven't seen a printable char yet */
  246.         while(cp != linebuf){
  247.         if (!isspace(cp[-1]))    /* Next is a printable char? */
  248.             seenprint = 1;
  249.         else
  250.             if (seenprint)    /* Next is a space, quit when we */
  251.             break;        /* already erased characters */
  252.         bschar(c = *--cp);
  253.         for(i = 0, p = cp, q = cp + 1; i < tailchars; i++){
  254.             echochar(p[1]);
  255.             *p++ = *q++;
  256.         }
  257.         erachar(c);
  258.         *p = '\0';
  259.         for(i = 0; i < tailchars; i++)
  260.             bschar(*--p);
  261.         }
  262.         break;
  263.     case -14:        /* down-arrow = next in history */
  264.         if(lh != NULLHIST && lh->prev != NULLHIST){
  265.         lh = lh->prev;
  266.         while(tailchars > 0){ /* move to end of line */
  267.             echochar(*cp++);
  268.             tailchars--;
  269.         }
  270.         while(cp != linebuf){ /* erase it */
  271.             bschar(*--cp);
  272.             erachar(*cp);
  273.         }
  274.         memset(linebuf,0,LINESIZE);
  275.         strcpy(linebuf,lh->linebuf);
  276.         for(cp = linebuf; *cp && *cp != '\r'; cp++){
  277.             echochar(*cp);
  278.         }
  279.         }
  280.         break;
  281.     case -12:        /* insert */
  282.         insmode ^= 1;    /* toggle insert mode */
  283.         break;
  284.     case -16:        /* right-arrow = buffer character */
  285.         insmode = 0;    /* insert mode screws things up */
  286.         if(*cp && *cp != '\r'){
  287.         c = *cp;
  288.         goto storechar;
  289.         }
  290.         break;
  291.     case -17:        /* left-arrow = nondestruct backspace */
  292.         if(cp != linebuf){
  293.         tailchars++;
  294.         bschar(*--cp);
  295.         }
  296.         break;
  297.     case -19:        /* up-arrow = prev in history */
  298.         if(lh != NULLHIST){
  299.         while(tailchars > 0){ /* move to end of line */
  300.             echochar(*cp++);
  301.             tailchars--;
  302.         }
  303.         while(cp != linebuf){ /* erase it */
  304.             bschar(*--cp);
  305.             erachar(*cp);
  306.         }
  307.         memset(linebuf,0,LINESIZE);
  308.         strcpy(linebuf,lh->linebuf);
  309.         if (lh->next != NULLHIST)
  310.             lh = lh->next;
  311.         for(cp = linebuf; *cp && *cp != '\r'; cp++)
  312.             echochar(*cp);
  313.         }
  314.         break;
  315.     case -20:        /* HOME = begin of line */
  316.         while(cp != linebuf){
  317.         tailchars++;
  318.         bschar(*--cp);
  319.         }
  320.         break;
  321.     case -15:        /* END = end of line */
  322.         while(tailchars > 0){
  323.         echochar(*cp++);
  324.         tailchars--;
  325.         }
  326.         break;
  327.     default:        /* Ordinary character */
  328.         if(c < 0)        /* a non-decoded special character? */
  329.         break;        /* ignore it */
  330.  
  331. storechar:
  332.         echochar(c);
  333.  
  334.         if(insmode && quote < 2){
  335.         for(i = 0, p = cp; i < tailchars; i++)
  336.             echochar(*p++);
  337.         for(i = 0, q = p + 1; i < tailchars; i++)
  338.             bschar(*--q = *--p);
  339.         } else {
  340.         if(tailchars > 0){
  341.             tailchars--;
  342.             if(c < ' ' || *cp < ' '){
  343.             for(i = 0, p = cp + 1; i < tailchars; i++)
  344.                 echochar(*p++);
  345.             erachar(' ');
  346.             for(i = 0; i < tailchars; i++)
  347.                 bschar(*--p);
  348.             }
  349.         }
  350.         }
  351.  
  352.         if(quote)
  353.         if(quote == 1){        /* immediately after ^V */
  354.             quote = 2;
  355.             bschar(c);        /* backspace to the '^' */
  356.